﻿/*
 * 作者：新生命开发团队（http://www.newlifex.com/）
 * 
 * 版权：版权所有 (C) 新生命开发团队 2002-2014
 * 
 * 修改：海洋饼干（cuteant@outlook.com）
*/

using System;
using System.Collections.Generic;
using CuteAnt.Configuration;
using CuteAnt.Log;

using CuteAnt.Reflection;

namespace CuteAnt.Model
{
	/// <summary>实现 <seealso cref="IObjectContainer"/> 接口的对象容器</summary>
	/// <remarks>
	/// 1，如果容器里面没有这个类型，则返回空；
	/// 2，如果容器里面包含这个类型，<see cref="ResolveInstance"/>返回单例；
	/// 3，如果容器里面包含这个类型，<see cref="Resolve(Type, Object, Boolean)"/>创建对象返回多实例；
	/// 4，如果有带参数构造函数，则从容器内获取各个参数的实例，最后创建对象返回。
	///
	/// 这里有一点跟大多数对象容器非常不同，其它对象容器会控制对象的生命周期，在对象不再使用时收回到容器里面。
	/// 这里的对象容器主要是为了用于解耦，所以只有最简单的功能实现。
	///
	/// 代码注册的默认优先级是0；
	/// 配置注册的默认优先级是1；
	/// 自动注册的外部实现（非排除项）的默认优先级是1，排除项的优先级是0；
	/// 所以，配置注册的优先级最高
	/// </remarks>
	public class ObjectContainer : IObjectContainer
	{
		#region -- 当前静态对象容器 --

		private static IObjectContainer _Current;

		/// <summary>当前容器</summary>
		public static IObjectContainer Current
		{
			get
			{
				if (_Current != null) { return _Current; }
				lock (typeof(ObjectContainer))
				{
					if (_Current != null) { return _Current; }

					return _Current = new ObjectContainer();
				}
			}
			set { _Current = value; }
		}

		#endregion

		#region -- 构造函数 --

		/// <summary>初始化一个对象容器实例，自动从配置文件中加载注册</summary>
		public ObjectContainer()
		{
			LoadConfig();
		}

		#endregion

		#region -- 对象字典 --

		#region - property Stores -

		private IDictionary<Type, IDictionary<Object, IObjectMap>> _stores = null;

		private IDictionary<Type, IDictionary<Object, IObjectMap>> Stores
		{
			get { return _stores ?? (_stores = new Dictionary<Type, IDictionary<Object, IObjectMap>>()); }
		}

		#endregion

		#region - method Find -

		/// <summary>不存在又不添加时返回空列表</summary>
		/// <param name="type"></param>
		/// <param name="add"></param>
		/// <returns></returns>
		private IDictionary<Object, IObjectMap> Find(Type type, Boolean add = false)
		{
			IDictionary<Object, IObjectMap> dic = null;
			if (Stores.TryGetValue(type, out dic)) { return dic; }

			if (!add) { return null; }

			lock (Stores)
			{
				if (Stores.TryGetValue(type, out dic)) { return dic; }

				// 名称不区分大小写
				//dic = new Dictionary<Object, IObjectMap>(StringComparer.OrdinalIgnoreCase);
				dic = new Dictionary<Object, IObjectMap>();
				Stores.Add(type, dic);
				return dic;
			}
		}

		#endregion

		#region - method FindMap -

		private IObjectMap FindMap(IDictionary<Object, IObjectMap> dic, Object id, Boolean extend = false)
		{
			if (dic == null || dic.Count <= 0) { return null; }

			IObjectMap map = null;

			// 名称不能是null，否则字典里面会报错
			if (id == null) { id = String.Empty; }

			// 如果找到，直接返回
			if (dic.TryGetValue(id, out map) || dic.TryGetValue(id + "", out map))
			{
				return map;
			}

			if (id == null || "" + id == String.Empty)
			{
				// 如果名称不为空，则试一试找空的
				if (dic.TryGetValue(String.Empty, out map))
				{
					return map;
				}
			}
			else if (extend)
			{
				// 如果名称为空，找第一个
				foreach (var item in dic.Values)
				{
					return item;
				}
			}
			return null;
		}

		#endregion

		#region - class Map -

		private class Map : IObjectMap
		{
			#region 属性

			private Object _Identity;

			/// <summary>名称</summary>
			public Object Identity
			{
				get { return _Identity; }
				set { _Identity = value; }
			}

			private String _TypeName;

			/// <summary>类型名</summary>
			public String TypeName
			{
				get { return _TypeName; }
				set { _TypeName = value; }
			}

			private Type _ImplementType;

			/// <summary>实现类型</summary>
			public Type ImplementType
			{
				get
				{
					if (_ImplementType == null && !TypeName.IsNullOrWhiteSpace())
					{
						_ImplementType = TypeName.GetTypeEx(true);
						if (_ImplementType == null)
						{
							throw new HmExceptionBase("无法找到类型{0}！", TypeName);
						}
					}
					return _ImplementType;
				}
				set { _ImplementType = value; }
			}

			private Int32 _Priority;

			/// <summary>优先级</summary>
			public Int32 Priority
			{
				get { return _Priority; }
				set { _Priority = value; }
			}

			private Boolean hasCheck = false;
			private Object _Instance;

			/// <summary>实例</summary>
			public Object Instance
			{
				get
				{
					if (_Instance != null || hasCheck) { return _Instance; }

					try
					{
						if (ImplementType != null)
						{
							_Instance = ImplementType.CreateInstance();
						}
					}
					catch { }
					hasCheck = true;
					return _Instance;
				}
				set
				{
					_Instance = value;
					if (value != null) { ImplementType = value.GetType(); }
				}
			}

			#endregion

			#region 方法

			public override String ToString()
			{
				return String.Format("[{0},{1}]", Identity, ImplementType != null ? ImplementType.Name : null);
			}

			#endregion
		}

		#endregion

		#endregion

		#region -- 注册核心 --

		/// <summary>注册</summary>
		/// <param name="from">接口类型</param>
		/// <param name="to">实现类型</param>
		/// <param name="instance">实例</param>
		/// <param name="id">标识</param>
		/// <param name="priority">优先级</param>
		/// <returns></returns>
		public virtual IObjectContainer Register(
				Type from, Type to, Object instance, Object id = null, Int32 priority = 0)
		{
			return Register(from, to, instance, null, id, priority);
		}

		/// <summary>注册</summary>
		/// <param name="from">接口类型</param>
		/// <param name="to">实现类型</param>
		/// <param name="instance">实例</param>
		/// <param name="typeName">类型名称</param>
		/// <param name="id">标识</param>
		/// <param name="priority">优先级</param>
		/// <returns></returns>
		private IObjectContainer Register(Type from, Type to, Object instance, String typeName, Object id, Int32 priority)
		{
			if (from == null) { throw new ArgumentNullException("from"); }
			// 名称不能是null，否则字典里面会报错
			if (id == null) { id = String.Empty; }

			var dic = Find(from, true);
			IObjectMap old = null;
			Map map = null;
			if (dic.TryGetValue(id, out old) || dic.TryGetValue(id + "", out old))
			{
				map = old as Map;
				if (map != null)
				{
					// 优先级太小不能覆盖
					if (priority <= map.Priority) { return this; }

					map.TypeName = typeName;
					map.ImplementType = to;
					map.Instance = instance;

					return this;
				}
				else
				{
					lock (dic)
					{
						dic.Remove(id);
					}
				}
			}

			map = new Map();
			map.Identity = id;
			map.TypeName = typeName;
			map.Priority = priority;
			if (to != null) { map.ImplementType = to; }
			if (instance != null) { map.Instance = instance; }

			if (!dic.ContainsKey(id))
			{
				lock (dic)
				{
					if (!dic.ContainsKey(id)) { dic.Add(id, map); }
				}
			}

			return this;
		}

		#endregion

		#region -- 注册 --

		/// <summary>遍历所有程序集的所有类型，自动注册实现了指定接口或基类的类型。如果没有注册任何实现，则默认注册第一个排除类型</summary>
		/// <remarks>自动注册一般用于单实例功能扩展型接口</remarks>
		/// <param name="from">接口或基类</param>
		/// <param name="excludeTypes">要排除的类型，一般是内部默认实现</param>
		/// <returns></returns>
		public virtual IObjectContainer AutoRegister(Type from, params Type[] excludeTypes)
		{
			return AutoRegister(from, null, null, 0, excludeTypes);
		}

		/// <summary>遍历所有程序集的所有类型，自动注册实现了指定接口或基类的类型。如果没有注册任何实现，则默认注册第一个排除类型</summary>
		/// <param name="from">接口或基类</param>
		/// <param name="getidCallback">用于从外部类型对象中获取标识的委托</param>
		/// <param name="id">标识</param>
		/// <param name="priority">优先级</param>
		/// <param name="excludeTypes">要排除的类型，一般是内部默认实现</param>
		/// <returns></returns>
		public virtual IObjectContainer AutoRegister(
				Type from, Func<Object, Object> getidCallback = null, Object id = null, Int32 priority = 0, params Type[] excludeTypes)
		{
			ValidationHelper.ArgumentNull(from, "from");
			if (excludeTypes == null) { excludeTypes = Type.EmptyTypes; }

			// 如果存在已注册项，并且优先级大于0，那么这里就不要注册了
			var dic = Find(from);
			if (dic != null && dic.Count > 0)
			{
				var map = FindMap(dic, null, false) as Map;
				if (map != null && map.Priority > 0) { return this; }
			}

			// 遍历所有程序集，自动加载
			foreach (var item in from.GetAllSubclasses(true))
			{
				if (Array.IndexOf(excludeTypes, item) < 0)
				{
					// 自动注册的优先级是1，高于默认的0
					//Register(from, item, null, null, 1);
					// 实例化一次，让这个类有机会执行类型构造函数，可以获取旧的类型实现
					var obj = item.CreateInstance();

					// 如果指定了获取ID的委托，并且取得的ID与传入ID不一致，则不承认
					if (getidCallback != null && id != getidCallback(obj)) { continue; }

					HmTrace.WriteDebug("为{0}自动注册{1}，标识={2}，优先级={3}！", from.FullName, item.FullName, id, priority + 1);

					Register(from, null, obj, id, priority + 1);
					return this;
				}
			}

			// 如果没有注册任何实现，则默认注册第一个排除类型
			if (excludeTypes.Length > 0)
			{
				Register(from, excludeTypes[0], null, id, priority);
			}
			return this;
		}

		#endregion

		#region -- 解析 --

		private Object Resolve(Type from, Boolean getInstance, Object id, Boolean extend)
		{
			ValidationHelper.ArgumentNull(from, "from");

			// 名称不能是null，否则字典里面会报错
			if (id == null) { id = String.Empty; }

			var dic = Find(from);
			// 不需要自动注册，用户可以自己调用自动注册，并且这样子会破坏架构
			//if (dic == null && id == String.Empty)
			//{
			//    // 再来一次，添加字典，确保这个自动搜索过程只执行一次
			//    dic = Find(from, true);

			//    // 遍历所有程序集，自动加载
			//    foreach (var item in from.GetAllSubclasses(true))
			//    {
			//        // 实例化一次，让这个类有机会执行类型构造函数，可以获取旧的类型实现
			//        var obj = item.CreateInstance();

			//        if (XTrace.Debug) XTrace.WriteLine("Resolve时为{0}自动注册{1}！", from.FullName, item.FullName);

			//        Register(from, null, obj);

			//        return getInstance ? obj : item.CreateInstance();
			//    }

			//    return null;
			//}

			// 1，如果容器里面没有这个类型，则返回空
			// 这个type可能是接口类型
			if (dic == null || dic.Count <= 0) { return null; }

			// 2，如果容器里面包含这个类型，并且指向的实例不为空，则返回
			// 根据名称去找，找不到返回空
			var map = FindMap(dic, id, extend);
			if (map == null) { return null; }
			// 如果就是为了取实例，直接返回
			if (getInstance) { return map.Instance; }
			// 否则每次都实例化

			// 检查是否指定实现类型，这种可能性极低，根本就不应该存在
			if (map.ImplementType == null) { throw new HmExceptionBase("设计错误，名为{0}的{1}实现未找到！", id, from); }

			// 3，如果容器里面包含这个类型，并且指向的实例为空，则创建对象返回。不再支持构造函数依赖注入
			return map.ImplementType.CreateInstance();
		}

		/// <summary>解析类型指定名称的实例</summary>
		/// <param name="from">接口类型</param>
		/// <param name="id">标识</param>
		/// <param name="extend">扩展。若为ture，id为null而找不到时，采用第一个注册项；id不为null而找不到时，采用null注册项</param>
		/// <returns></returns>
		public virtual Object Resolve(Type from, Object id = null, Boolean extend = false)
		{
			return Resolve(from, false, id, extend);
		}

		/// <summary>解析类型指定名称的实例</summary>
		/// <param name="from">接口类型</param>
		/// <param name="id">标识</param>
		/// <param name="extend">扩展。若为ture，id为null而找不到时，采用第一个注册项；id不为null而找不到时，采用null注册项</param>
		/// <returns></returns>
		public virtual Object ResolveInstance(Type from, Object id = null, Boolean extend = false)
		{
			return Resolve(from, true, id, extend);
		}

		#endregion

		#region -- 解析类型 --

		/// <summary>解析接口指定名称的实现类型</summary>
		/// <param name="from">接口类型</param>
		/// <param name="id">标识</param>
		/// <param name="extend">扩展。若为ture，name为null而找不到时，采用第一个注册项；name不为null而找不到时，采用null注册项</param>
		/// <returns></returns>
		public virtual Type ResolveType(Type from, Object id = null, Boolean extend = false)
		{
			if (from == null) { throw new ArgumentNullException("from"); }
			// 名称不能是null，否则字典里面会报错
			if (id == null) { id = String.Empty; }

			var map = FindMap(Find(from), id, extend);
			if (map == null) { return null; }

			return map.ImplementType;
		}

		/// <summary>解析接口所有已注册的对象映射</summary>
		/// <param name="from">接口类型</param>
		/// <returns></returns>
		public virtual IEnumerable<IObjectMap> ResolveAll(Type from)
		{
			var dic = Find(from);
			if (dic != null)
			{
				return Find(from).Values;
			}
			else
			{
				return new List<IObjectMap>();
			}
		}

		#endregion

		#region -- Xml配置文件注册 --

		/// <summary>加载配置</summary>
		protected virtual void LoadConfig()
		{
			var config = SystemConfigs.GetConfig();
			if (config.ObjectContainerItems == null || config.ObjectContainerItems.Length < 1) { return; }

			foreach (var item in config.ObjectContainerItems)
			{
				var name = item.Interface;
				if (name.IsNullOrWhiteSpace()) { continue; }
				var type = name.GetTypeEx(true);
				if (type == null)
				{
					HmTrace.WriteWarn("未找到对象容器配置{0}中的类型{1}！", item.Interface, name);
					continue;
				}
				var map = GetConfig(item);
				if (map == null) { continue; }

				HmTrace.WriteDebug("为{0}配置注册{1}，标识Identity={2}，优先级Priority={3}！", type.FullName, map.TypeName, map.Identity, map.Priority);

				Register(type, null, null, map.TypeName, map.Identity, map.Priority);
			}
		}

		/// <summary></summary>
		/// <param name="item"></param>
		/// <returns></returns>
		private static Map GetConfig(SystemConfigInfo.ObjectContainerItem item)
		{
			var map = new Map();

			map.Identity = item.Name;
			map.TypeName = item.Type;
			map.Priority = item.Priority;

			return map;
		}

		#endregion

		#region -- 辅助 --

		/// <summary>已重载。</summary>
		/// <returns></returns>
		public override String ToString()
		{
			return String.Format("{0}[Count={1}]", this.GetType().Name, Stores.Count);
		}

		#endregion
	}
}